package com.atguigu.gmall.activity.receiver;

import com.atguigu.gmall.activity.mapper.SeckillGoodsMapper;
import com.atguigu.gmall.activity.service.SeckillGoodsService;
import com.atguigu.gmall.common.config.constant.MqConst;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.DateUtil;
import com.atguigu.gmall.model.activity.OrderRecode;
import com.atguigu.gmall.model.activity.SeckillGoods;
import com.atguigu.gmall.model.activity.UserRecode;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.rabbitmq.client.Channel;
import lombok.SneakyThrows;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.List;

/**
 * @author atguigu-mqx
 */
@Component
public class SeckillReceiver {

    @Autowired
    private SeckillGoodsMapper seckillGoodsMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private SeckillGoodsService seckillGoodsService;

    @SneakyThrows
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_TASK_1,durable = "true",autoDelete = "false"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_TASK),
            key = {MqConst.ROUTING_TASK_1}
    ))
    public void importToRedis(Message message, Channel channel){
        try {
            //  查询数据库 当天秒杀的数据！，并将数据放入缓存！
            //  new date(); status = 1 ; stock_count > 0;
            QueryWrapper<SeckillGoods> seckillGoodsQueryWrapper = new QueryWrapper<>();
            seckillGoodsQueryWrapper.eq("status","1").gt("stock_count",0);
            //  new Date();Thu Sep 30 14:58:59 CST 2021
            seckillGoodsQueryWrapper.eq("DATE_FORMAT(start_time,'%Y-%m-%d')", DateUtil.formatDate(new Date()));

            //  获取到当前秒杀商品的集合列表！
            List<SeckillGoods> seckillGoodsList = seckillGoodsMapper.selectList(seckillGoodsQueryWrapper);
            //  循环遍历：
            if (!CollectionUtils.isEmpty(seckillGoodsList)){
                for (SeckillGoods seckillGoods : seckillGoodsList) {
                    //  必须了解使用那种数据类型存储? key ！ hset key=seckill:goods field=skuId value=seckillGoods;
                    String seckillKey = RedisConst.SECKILL_GOODS;
                    //  做个判断是否要写入缓存！
                    Boolean flag = this.redisTemplate.boundHashOps(seckillKey).hasKey(seckillGoods.getSkuId().toString());
                    //  缓存中有这个商品数据，不需要写入了。
                    if (flag){
                        //  return;  结束方法！
                        //  break;  跳出当前循环
                        continue;   //  结束本次循环，继续下次循环！
                    }
                    //  缓存中没有这个商品，写入数据.
                    this.redisTemplate.boundHashOps(seckillKey).put(seckillGoods.getSkuId().toString(),seckillGoods);
                    //  将商品的单个库存进行存储到list 数据类型中！
                    for (Integer i = 0; i < seckillGoods.getStockCount(); i++) {
                        //  每循环一次将数据添加到list 数据类型中！
                        //  key = seckill:stock:skuId   value = skuId.toString();
                        this.redisTemplate.opsForList().leftPush(RedisConst.SECKILL_STOCK_PREFIX+seckillGoods.getSkuId(),seckillGoods.getSkuId().toString());
                    }

                    //  需要做一个初始化操作！让每个秒杀的商品都应该是 1
                    //  publish seckillpush skuId:1
                    this.redisTemplate.convertAndSend("seckillpush",seckillGoods.getSkuId()+":1");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        //  消息确认
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }

    //  监听消息： userId , skuId
    @SneakyThrows
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_SECKILL_USER,durable = "true",autoDelete = "false"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_SECKILL_USER),
            key = {MqConst.ROUTING_SECKILL_USER}
    ))
    public void seckillUser(UserRecode userRecode,Message message,Channel channel){
        try {
            //  判断
            if(userRecode!=null){
                //  编写监听消息的业务逻辑： 1. 判断状态位。 2. 判断用户是否已经下过订单
                //  3. 减少库存，更新库存。如果减库存失败，通知其他兄弟节点 4. 将订单记录放入缓存！
                seckillGoodsService.seckillOrder(userRecode.getSkuId(),userRecode.getUserId());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        //  手动确认：
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }

    //  清空缓存数据！
    @SneakyThrows
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_TASK_18,durable = "true",autoDelete = "false"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_TASK),
            key = {MqConst.ROUTING_TASK_18}
    ))
    public void clearData(Message message, Channel channel){
        //  清空数据
        try {
            //  先查询到哪些数据应该删除！
            QueryWrapper<SeckillGoods> seckillGoodsQueryWrapper = new QueryWrapper<>();
            seckillGoodsQueryWrapper.eq("status",1);
            seckillGoodsQueryWrapper.le("end_time",new Date());
            //  获取到秒杀结束的商品列表
            List<SeckillGoods> seckillGoodsList = seckillGoodsMapper.selectList(seckillGoodsQueryWrapper);
            //  循环遍历
            for (SeckillGoods seckillGoods : seckillGoodsList) {
                //  循环遍历
                //  删除秒杀商品skuId
                this.redisTemplate.boundHashOps(RedisConst.SECKILL_GOODS).delete(seckillGoods.getSkuId().toString());
                //  删除剩余库存
                this.redisTemplate.delete(RedisConst.SECKILL_STOCK_PREFIX+seckillGoods.getSkuId());
            }
            //  如果每次只发一个秒杀商品！
            //  this.redisTemplate.delete(RedisConst.SECKILL_GOODS);
            //  删除真正的订单信息：
            this.redisTemplate.delete(RedisConst.SECKILL_ORDERS_USERS);
            //  seckill:user:1 userId 判断用户是否下过订单！

            //  预下单记录一定会被删除么? 张三买的商品！ 李四买的商品都这个这个预下单记录中！
            this.redisTemplate.delete(RedisConst.SECKILL_ORDERS);
            //  可以通过 hvals 获取到商品的集合列表
            List<OrderRecode> orderRecodeList = this.redisTemplate.boundHashOps(RedisConst.SECKILL_ORDERS).values();
            //  循环遍历
            for (OrderRecode orderRecode : orderRecodeList) {
                //  商品结束时间 < 当前系统时间
                if (DateUtil.dateCompare(orderRecode.getSeckillGoods().getEndTime(),new Date())){
                    this.redisTemplate.boundHashOps(RedisConst.SECKILL_ORDERS).delete(orderRecode.getUserId());
                }
            }
            //  修改数据库：
            SeckillGoods seckillGoods = new SeckillGoods();
            seckillGoods.setStatus("2");
            seckillGoodsMapper.update(seckillGoods,seckillGoodsQueryWrapper);
        }catch (Exception e){
            e.printStackTrace();
        }
        //  手动确认：
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }
}
